
template <class type> class Grid
{
public:
    Grid();
    Grid(unsigned int Rows, unsigned int Cols);
    Grid(unsigned int Rows, unsigned int Cols, const type &clearValue);
    Grid(const Grid<type> &G);
    //Grid(Grid &&G);
    
    ~Grid();

    //
    // Memory
    //
    void FreeMemory();
    void operator = (const Grid<type> &G);
    //void operator = (Grid &&G);
    void Allocate(unsigned int Rows, unsigned int Cols);
    void Allocate(unsigned int Rows, unsigned int Cols, const type &clearValue);
    
    //
    // Accessors
    //
    inline type& operator() (unsigned int Row, unsigned int Col)
    {
#ifdef VECTOR_DEBUG
        Assert( (Row < _rows) && (Col < _cols), "Out-of-bounds grid access");
#endif
        return _data[Row * _cols + Col];
    }
    inline const type& operator() (unsigned int Row, unsigned int Col) const
    {
#ifdef VECTOR_DEBUG
        Assert( (Row < _rows) && (Col < _cols), "Out-of-bounds grid access");
#endif
        return _data[Row * _cols + Col];
    }
    inline unsigned int Rows() const
    {
        return _rows;
    }
    inline unsigned int Cols() const
    {
        return _cols;
    }
    inline Vec2i Dimensions() const
    {
        return Vec2i(_rows, _cols);
    }
    inline bool Square() const
    {
        return (_rows == _cols);
    }
    inline type* CArray()
    {
        return _data;
    }
    inline const type* CArray() const
    {
        return _data;
    }
    
    //
    // Query
    //
    inline bool ValidCoordinates(int Row, int Col) const
    {
        return (Row >= 0 && Row < int(_rows) && Col >= 0 && Col < int(_cols));
    }

    Vec2i MaxIndex() const;
    const type& MaxValue() const;
    Vec2i MinIndex() const;
    const type& MinValue() const;

    //
    // Modifiers
    //
    void Clear(const type &T);

protected:
    type *_data;
    unsigned int _rows, _cols;
};

#include "grid.inl"
